library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity statemachine is
  port( start_stop_sync, lap_reset_sync, clk : in std_logic;
        is_running, is_lapped, reset : out std_logic );
end entity statemachine;

architecture statemachine_behavioral of statemachine is
--begin
--state_transition: process(start_stop_sync,lap_reset_sync,previous_state) is

type state_name is (STOPPED_AND_RESET,STARTED,LAPPED,LAPPED_AND_STOPPED,STOPPED);
type state_type is record
state: state_name;
is_running: std_logic;
is_lapped: std_logic;
reset: std_logic;
end record;

signal next_state: state_type:=(STOPPED_AND_RESET, '0','0','1');
signal previous_state: state_type:=(STOPPED_AND_RESET, '0','0','1');

begin
  
  combinational_block: process(start_stop_sync,lap_reset_sync,previous_state) is
  variable temporary_state: state_type:=(STOPPED_AND_RESET, '0','0','1');
  begin
    temporary_state:=previous_state;
    case temporary_state.state is
      
    when STOPPED_AND_RESET =>
      
      if start_stop_sync='1' then
        temporary_state.state := STARTED;
        temporary_state.is_running := '1';
        temporary_state.is_lapped := '0';
        temporary_state.reset := '0';
      else
        NULL;
      end if;
      
    when STARTED =>
      
      if start_stop_sync='1' then
        temporary_state.state := STOPPED;
        temporary_state.is_running := '0';
        temporary_state.is_lapped := '0';
        temporary_state.reset := '0';
      elsif lap_reset_sync='1'then
        temporary_state.state := LAPPED;
        temporary_state.is_running := '1';
        temporary_state.is_lapped := '1';
        temporary_state.reset := '0';
      else
        NULL;
      end if;
      
    when LAPPED =>
      
      if start_stop_sync='1' then
        temporary_state.state := LAPPED_AND_STOPPED;
        temporary_state.is_running := '0';
        temporary_state.is_lapped := '1';
        temporary_state.reset := '0';
      elsif lap_reset_sync='1'then
        temporary_state.state := STARTED;
        temporary_state.is_running := '1';
        temporary_state.is_lapped := '0';
        temporary_state.reset := '0';
      else
        NULL;
      end if;
      
    when LAPPED_AND_STOPPED =>
      
      if start_stop_sync='1' then
        temporary_state.state := LAPPED;
        temporary_state.is_running := '1';
        temporary_state.is_lapped := '1';
        temporary_state.reset := '0';
      elsif lap_reset_sync='1'then
        temporary_state.state := STOPPED_AND_RESET;
        temporary_state.is_running := '0';
        temporary_state.is_lapped := '0';
        temporary_state.reset := '1';
      else
        NULL;
      end if;
      
    when STOPPED =>
      
      if start_stop_sync='1' then
        temporary_state.state := STARTED;
        temporary_state.is_running := '1';
        temporary_state.is_lapped := '0';
        temporary_state.reset := '0';
      elsif lap_reset_sync='1'then
        temporary_state.state := STOPPED_AND_RESET;
        temporary_state.is_running := '0';
        temporary_state.is_lapped := '0';
        temporary_state.reset := '1';
      else
        NULL;
      end if;
    end case;
    
    is_running <= temporary_state.is_running;
    is_lapped <= temporary_state.is_lapped;
    reset <= temporary_state.reset;
    next_state <= temporary_state;
    
  end process combinational_block;
  
  sequential_block: process(clk) is
  begin
    
    if rising_edge(clk) then
      previous_state <= next_state;
    end if;
  end process sequential_block;

end architecture statemachine_behavioral;
-----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity synchronous_posedges is
  port( i, clk : in std_logic;
        o : out std_logic := '0' );
end entity synchronous_posedges;

architecture behavioral of synchronous_posedges is
begin
  spe_beh : process(clk) is
    variable last_i : std_logic := '0';
  begin
    if rising_edge(clk) then
      if i = '1' and last_i = '0' then
        o <= '1';
      else
        o <= '0';
      end if;
      last_i := i;
    end if;
  end process spe_beh;
end architecture behavioral;
---------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity state_machine_test_bench is
  port( clk : in std_logic;
        is_running,is_lapped, reset : out std_logic := '0' );
end entity state_machine_test_bench;

architecture state_machine_test_bench_arch of state_machine_test_bench is
  signal ss_sync,lr_sync:std_logic;
  signal start_stop,lap_reset:std_logic;
  begin
    
    sync1 : entity work.synchronous_posedges(behavioral) port map (start_stop, clk, ss_sync);
    sync2 : entity work.synchronous_posedges(behavioral) port map (lap_reset, clk, lr_sync);

    statm : entity work.statemachine(statemachine_behavioral) port map (ss_sync, lr_sync,clk,
                                                         is_running, is_lapped, reset);
    -- started&stopped to started&stopped
    
--    start_stop <= '0', '1' after 0.1 us, '0' after 0.2 us;
    
    -- started&stopped to started&stopped
    
    start_stop <= '0', '1' after 0.1 us, '0' after 0.2 us, '1' after 0.7 us, '0' after 0.9 us;
    lap_reset <= '0','1' after 0.4 us, '0' after 0.6 us;
    
                                                         
end architecture state_machine_test_bench_arch;
-------------------------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity counter is
  generic( bits : natural;
           bound : integer );
  port( clk, count, reset : in std_logic;
        o : out unsigned(0 to bits-1);
        carry : out std_logic );
end entity counter;

architecture behavioral of counter is
  
signal previous_count,next_count: unsigned(0 to bits-1) := (others => '0');

begin
  
  combinational_block: process(count,reset,previous_count) is
    variable tmp_count:unsigned(0 to bits-1):= (others => '0');
    variable one_count:unsigned(0 to bits-1) := (bits-1 => '1',others => '0');
    variable bound_binary:unsigned(0 to bits-1) := to_unsigned(bound,bits);
    variable all_zeros:unsigned(0 to bits-1):= (others => '0');
    variable wrap_around :std_logic := '0';

    begin
                  
      tmp_count := previous_count;

      if reset='1' then
        tmp_count := (others => '0');

      elsif count='1' then
          tmp_count:=tmp_count + one_count;    
          if tmp_count = bound_binary then
            tmp_count := (others => '0');
            wrap_around := '1';
          end if;
          carry <= '0';
      end if;
      
      if tmp_count = all_zeros and wrap_around = '1' then
        carry <= '1';
        wrap_around := '0';
      else
        carry <= '0';
      end if;      
      o <= tmp_count;
      next_count <= tmp_count;    
  end process combinational_block;
  
  sequential_block: process(clk,reset) is
  begin
    if reset = '1' then
      previous_count <= (others => '0');
    elsif rising_edge(clk) then
      previous_count <= next_count;
    end if;
  end process sequential_block;
end architecture behavioral;
--------------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity counter_testbench is
  port( clk, count, reset : in std_logic;
        o : out unsigned(0 to 3);
        carry : out std_logic );
end entity counter_testbench;

architecture counter_testbench_behavioral of counter_testbench is
  
  signal carry0,c_in1_trigger : std_logic := '0';
  signal deci_tick_op : unsigned(0 to 3) := (others => '0');
  
begin
  
  counter_instance0 : entity work.counter(behavioral) generic map(4,10) port map(clk,count,reset,deci_tick_op,carry0);
  counter_instance1 : entity work.counter(behavioral) generic map(4,10) port map(clk,carry0,reset,o,carry);

end architecture counter_testbench_behavioral;
-------------------------------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

package our_types is
  type display_type is record
    min1 : unsigned(0 to 3);
    min0 : unsigned(0 to 3);
    sec1 : unsigned(0 to 3);
    sec0 : unsigned(0 to 3);
    hun1 : unsigned(0 to 3);
    hun0 : unsigned(0 to 3);
  end record display_type;
end package our_types;

--------------------------------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.our_types.all;

entity sw_counter_testbench is
  port( clk, count, reset : in std_logic;
        display : out display_type);
end entity sw_counter_testbench;

architecture behavioral of sw_counter_testbench is
  
  signal deci_carry,hun1_carry,hun0_carry,sec1_carry,sec0_carry,min1_carry,min0_carry : std_logic := '0';
  signal hun_0_trigger,sec_1_trigger,sec_0_trigger,min_1_trigger,min_0_trigger : std_logic := '0';
  signal deci_tick_op : unsigned(0 to 9) := (others => '0');

begin
  
  deci_tick : entity work.counter(behavioral) generic map(10,1000) port map(clk,count,reset,deci_tick_op,deci_carry);
  
  hun1 : entity work.counter(behavioral) generic map(4,10) port map(clk,deci_carry,reset,display.hun1,hun1_carry);   
  hun1_sync_posedge : entity work.synchronous_posedges(behavioral) port map (hun1_carry, clk, hun_0_trigger);
  hun0 : entity work.counter(behavioral) generic map(4,10) port map(clk,hun_0_trigger,reset,display.hun0,hun0_carry);  
  hun0_sync_posedge : entity work.synchronous_posedges(behavioral) port map (hun0_carry, clk, sec_1_trigger);
  sec1 : entity work.counter(behavioral) generic map(4,10) port map(clk,sec_1_trigger,reset,display.sec1,sec1_carry);
  sec1_sync_posedge : entity work.synchronous_posedges(behavioral) port map (sec1_carry, clk, sec_0_trigger);
  sec0 : entity work.counter(behavioral) generic map(4,6) port map(clk,sec_0_trigger,reset,display.sec0,sec0_carry);
  sec0_sync_posedge : entity work.synchronous_posedges(behavioral) port map (sec0_carry, clk, min_1_trigger);
  min1 : entity work.counter(behavioral) generic map(4,10) port map(clk,min_1_trigger,reset,display.min1,min1_carry);
  min_sync_posedge : entity work.synchronous_posedges(behavioral) port map (min1_carry, clk, min_0_trigger);
  min0 : entity work.counter(behavioral) generic map(4,6) port map(clk,min_0_trigger,reset,display.min0,min0_carry);
    

end architecture behavioral;

--------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity holder is
  generic( bits: natural );
  port( clk, hold : in std_logic;
        i: in unsigned(0 to bits-1);
        o: out unsigned(0 to bits-1) );
end entity holder;

architecture behavioral of holder is
  signal old_value: unsigned(0 to bits-1) := (others => '0');
begin
  comb : process(hold, i) is
  begin
    if hold='1' then
      o <= old_value;
    else
      o <= i;
    end if;
  end process comb;

  seq : process(clk) is
  begin
    if rising_edge(clk) then
      if hold='1' then
        old_value <= old_value;
      else
        old_value <= i;
      end if;
    end if;
  end process seq;
end architecture behavioral;
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.our_types.all;

entity holder_testbench is
  port( clk,count,hold : in std_logic;        
        o: out unsigned(3 downto 0) );
end entity holder_testbench;

architecture behavioral of holder_testbench is
  signal i: unsigned(3 downto 0) := (others => '0'); 
  signal c0_carry : std_logic := '0';
  begin
    c0: entity work.counter(behavioral) generic map(4,10) port map(clk,count,'0',i,c0_carry);
    h0: entity work.holder(behavioral) generic map(4) port map(clk,hold,i,o);
end architecture behavioral;
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.our_types.all;

entity stopwatch_rtl is
  port( clk,start_stop,lap_reset : in std_logic;
        lapped_display : out display_type);
end entity stopwatch_rtl;

architecture behavioral of stopwatch_rtl is
  signal ss_sync,lr_sync,is_running,is_lapped,reset:std_logic :='0';
  signal display : display_type := ("0000","0000","0000","0000","0000","0000");
  signal deci_carry,hun1_carry,hun0_carry,sec1_carry,sec0_carry,min1_carry,min0_carry : std_logic := '0';
  signal hun_0_trigger,sec_1_trigger,sec_0_trigger,min_1_trigger,min_0_trigger : std_logic := '0';
  signal deci_tick_op : unsigned(0 to 9) := (others => '0');
  
begin
  
  sync1 : entity work.synchronous_posedges(behavioral) port map (start_stop, clk, ss_sync);
  sync2 : entity work.synchronous_posedges(behavioral) port map (lap_reset, clk, lr_sync);
  
  statm : entity work.statemachine(statemachine_behavioral) port map (ss_sync, lr_sync,clk,is_running,is_lapped, reset);
    
  deci_tick : entity work.counter(behavioral) generic map(10,1000) port map(clk,is_running,reset,deci_tick_op,deci_carry);
  
  hun1 : entity work.counter(behavioral) generic map(4,10) port map(clk,deci_carry,reset,display.hun1,hun1_carry);   
  hold_hun1: entity work.holder(behavioral) generic map(4) port map(clk,is_lapped,display.hun1,lapped_display.hun1);  
    
  hun1_sync_posedge : entity work.synchronous_posedges(behavioral) port map (hun1_carry, clk, hun_0_trigger);
  hun0 : entity work.counter(behavioral) generic map(4,10) port map(clk,hun_0_trigger,reset,display.hun0,hun0_carry);  
  hold_hun0: entity work.holder(behavioral) generic map(4) port map(clk,is_lapped,display.hun0,lapped_display.hun0);  

  hun0_sync_posedge : entity work.synchronous_posedges(behavioral) port map (hun0_carry, clk, sec_1_trigger);
  sec1 : entity work.counter(behavioral) generic map(4,10) port map(clk,sec_1_trigger,reset,display.sec1,sec1_carry);
  hold_sec1: entity work.holder(behavioral) generic map(4) port map(clk,is_lapped,display.sec1,lapped_display.sec1);  

  sec1_sync_posedge : entity work.synchronous_posedges(behavioral) port map (sec1_carry, clk, sec_0_trigger);
  sec0 : entity work.counter(behavioral) generic map(4,6) port map(clk,sec_0_trigger,reset,display.sec0,sec0_carry);
  hold_sec0: entity work.holder(behavioral) generic map(4) port map(clk,is_lapped,display.sec0,lapped_display.sec0);      

  sec0_sync_posedge : entity work.synchronous_posedges(behavioral) port map (sec0_carry, clk, min_1_trigger);
  min1 : entity work.counter(behavioral) generic map(4,10) port map(clk,min_1_trigger,reset,display.min1,min1_carry);
  hold_min1: entity work.holder(behavioral) generic map(4) port map(clk,is_lapped,display.min1,lapped_display.min1);      

  min_sync_posedge : entity work.synchronous_posedges(behavioral) port map (min1_carry, clk, min_0_trigger);
  min0 : entity work.counter(behavioral) generic map(4,6) port map(clk,min_0_trigger,reset,display.min0,min0_carry);
  hold_min0: entity work.holder(behavioral) generic map(4) port map(clk,is_lapped,display.min0,lapped_display.min0);        
  
end architecture behavioral;
    
                      